package Torgi_bryansk_ru;
use strict;
use warnings;
use Encode;
use Data::Dumper;
use WWW::Mechanize;
#use WWW::Scripter;

#> Переменная $enabled указывает запускать модуль при сканировании или нет.
my $enabled = 0; # 1/0 - edit to enable/disable module

#> Переменная $site_address указывает базовый url из которого формируются все остальные пути к страницам.
my $site_address = 'http://www.torgi.bryansk.ru';


sub explore{
 #> Существование функции explore предполагается в каждом сканирующем модуле.
 #> Возвращает 1 или 0. Возврат 0 указывает вызывающему, что была ошибка.
 #> Вызывающий может прочитать текст ошибки методом error данного модуля.
 #> Метод explore вызывается модулем CleverBot.pm в функции launch.
 #> При этом передается параметр $c - "контект", ссылка на объект модуля CleverBot.pm
 #> Внутри тела принимается два параметра:
 #> $self - как всегда при вызове метода объекта в Perl принимается ссылка на себя.
 #> $c - тот самый объект $cb , представляющий CleverBot.pm
 #> Объект $c предоставляет текущему модулю доступ ко всем своим методам и переменным (см. описание CleverBot.pm), 
 #> чем сканирующий модуль и пользуется при своей работе.
 my ( $self, $c ) = @_;
 return 1 if !$enabled;
 
 $c->debug_call("call explore conf=".$c->conf('user_agent')."\n");
 
 #> В процессе своей работы модуль должен заносить новые конкурсы в БД путем вызова метода set_news объекта $c.
 #> В метод будет передаваться сруктура с именем $news - ссылка на хеш-массив.
 #> Т.к. вызов set_news всегда идет внутри какого-то цикла, перебирающего вносимые конкурсы,
 #> то удобно заранее создать структуру и поля, которые не меняются.
 #> Заготовка этой структуры выглядит примерно так:
 #>c my $news = {
 #>c	site => $site_address,
 #>c	id => undef,
 #>c	url => undef,
 #>c	small_text => undef,
 #>c	customer => undef,
 #>c }; 
 #> По ходу цикла те поля, которые сейчас undef - будут заполняться/изменяться.
 
 my $news = {
	site => $site_address,
	id => undef,
	url => undef,
	small_text => undef,
	customer => undef,
 }; # - base structure

 #> Создается новый объект WWW::Mechanize, который используется для получения содержимого с сайтов.
 #> Описание см. <a href=http://search.cpan.org/search?query=WWW-mechanize&mode=all>http://search.cpan.org/search?query=WWW-mechanize&mode=all</a>.
 #$c->debug_explain(" new WWW_Mechanize\n");
 my $m = WWW::Mechanize->new( cookie_jar => {} );
 
 
 my $total_inserted = 0; # сколько всего залито новостей

 # Массив @targets описывает
 # разделы идентичной структуры по которым нужно пройтись:
 my @targets = ( 
    { 
	url => "$site_address/index.php?option=com_content&task=category&sectionid=10&id=5&Itemid=13", 
#	form_name => 'aspnetForm',
#	form_pars =>{
#	    'ctl00$phWorkZone$pf$txt_sb'=>'Брянская область',
#	    'ctl00$phWorkZone$pf$rp_r$ctl07$cb'=>"32",
#	    '__EVENTTARGET'   => 'ctl00$phWorkZone$pf$btn_f',
#	    '__EVENTARGUMENT' => '',
#	}, 
#	click_name => 'ctl00$phWorkZone$pf$btn_fb',
	page_n => 1,
    }, 
#    {
#	form_name => 'aspnetForm',
#	form_pars =>{
#	    '__EVENTTARGET'  =>'ctl00$phWorkZone$ListOfNewPurchase$gvMain',
#	    '__EVENTARGUMENT'=>'Page$2',
#	}, 
#	page_n => 2,
#    },
 ); 

 #> Функция insert_from_page, занимающаяся анализом нужной страницы и заносящая конкурсы в БД, вызывается в цикле для разных страниц.
 for my $target ( @targets ){
    my $current_inserted = $self->insert_from_page( c=>$c, news=>$news, m=>$m, target=>$target, );
    defined $current_inserted or return 0;
    $total_inserted += $current_inserted;
 }
 #> После занесения конкурсов  вызывается $c->set_stat , для сохранения статистики в таблице stat,.
 $c->set_stat( name_en=>"inserted_from_$site_address", name_ru=>"Последнее добавление с $site_address", val=>$total_inserted, 
    comment=>"(кол-во всех новых конкурсов)"  )  if $total_inserted; 

 return 1; # this say: "Ok or not"
}
 
sub insert_from_page{
 #> Return number of real inserted_news.
 
 my $self = shift;
 my %pars = @_;
 
 #> Params:
 #> c - "context" - $c object
 my $c = $pars{c} or die "c!";
 
 #> m - WWW::Mechanize object
 my $m = $pars{m} or die "m!";
 
 #> news - hesh-ref
 my $news = $pars{news} or die "news!";
 
 #> target - hash ref with:
 #>c {
 #>c 	url => $url
 #>c 	form_name => 'aspnetForm',
 #>c 	form_pars =>{
 #>c 	    field_name1 => 'value1',
 #>c 	    field_name2 => 'val2',
 #>c 	}, 
 #>c 	click_name => "name of submit button",
 #>c 	page_n => page number,
 #>c }

 my $target = $pars{target} or die "target!";
 ref $target eq "HASH" or die "target most be a hash ref! ". Dumper($target);
 my $url = $target->{url};#  or die "url!";
 my %form_pars;
 %form_pars = %{ $target->{form_pars} } if ref $target->{form_pars} eq "HASH";
# %form_pars or die "form_pars!"; # - disable, if form_pars may be empty
 my $form_name = $target->{form_name};
 my $click_name = $target->{click_name};# or die "click_name!";
 my $page_n = $target->{page_n} or die "page_n!";
 
 my $co;

 $c->debug_explain( "Called 'insert_from_page'".Dumper($target) );
 
 if ( $url ){
    #> Если указан $target->{url}, то переходит по адресу url.
    $c->debug_explain("Get url=$url\n");
    $m->get( $url );
 }
 
 
 if ( %form_pars ){ 
    #> Если указан $target->{form_pars} то html-форма на странице заполняется соответствующими значениями и нажимается кнопка click_name.
    die "form_name!" if !$form_name;
    # open search form and set search parameters in form:
     #//debug:
#     $co = $m->content;
#     $co = encode("cp1251",$co);
#     open TEST, ">test" or die $!;
#     print TEST $co;
#    # $m->dump_forms;
#     close TEST;
#    `firefox test`;
#    die;    
     # - end of debug.
    $c->debug_explain("Form_name: '$form_name'. Set form_pars:".Dumper(\%form_pars)." in form.\n");
    my @forms = $m->forms;
    if ( !@forms ){
	my $msg = "NO FORMS FOUND in this page. Possible page not load from inet. Try later.  \n";
	$c->debug_explain($msg);
	warn $msg;
	return 0;
    }
    $m->form_name( $form_name );
    for my $key ( keys %form_pars ){
	$m->field( $key,$form_pars{$key} );
    }
    if ( $click_name ){
        $c->debug_explain("Click '$click_name' ...\n");
        $m->click( $click_name ); #ctl00$phWorkZone$pf$btn_fb	
    }else{
	#> Если click_name не указано, то нажимается кнопка submit.
	$c->debug_explain("Submit ...\n");
	$m->submit();
    }

    # then we have a search result
#    open TEST, ">test" or die $!;
#    $co = $m->content;
#    $co = encode("cp1251",$co);
#    print TEST $co;
#    close TEST;
#    `firefox test`;
#    die;

    $c->debug_explain("Return status: ".$m->status()."\n");
 }

 $co = $m->content;
 
 #> В процессе работы сканирующие модули сохраняют информацию о ходе работы в файлы.
 #> Каждый - в свою папку , ее имя он берет из $c->{data_dir}, обычно это имя_модуля+.data
 my $data_dir = $c->{data_dir} or die "dir!";
 
 #> В файлик $data_dir/list_of_$page_n.list сохраняется содержимое анализируемой страницы.
 my $current_file = "$data_dir/list_of_$page_n.list";
 open FILE, ">$current_file" or die "Can't open $current_file: $!";
 $co = encode("utf8",$co);
 print FILE $co;
 close FILE;
#     `firefox $current_file`;
 
 #> В файл $data_dir/links_$page_n.list будет сохраняться список ссылок найденных на странице.
 my $links_file = "$data_dir/links_$page_n.list";
 
 #> В х-массив %l попадаеют пары url=>название. Они формируются поиском регулярного выражения в содержимом страницы.
 my %l = $co =~ 
 m|\<tr\s+class\=\"sectiontableentry.*?\<a\s+href\=\"index.php\?option\=com_content\&amp\;task\=view\&amp\;id\=(\d+)\&amp\;Itemid\=13\"\>\s*(.+?)\s*\<\/a\>|imsg;
 $c->debug_explain("Founded links:", Dumper \%l , "It will Saved into file '$links_file'.");
     
 open FILE , ">$links_file" or die "Can't open $links_file: $!";
 print FILE "$_ | $l{$_} \n" for keys %l;
 close FILE;
#`firefox $links_file`;

 my $inserted_cnt = 0;
 for my $key ( keys %l ){

    $news->{ id } = $key;
    $news->{ url } = "index.php?option=com_content&task=view&id=$key&Itemid=13";
    $news->{ small_text } = "$l{$key}";
    
    #customer lke a small_text:
    # не знаю как выдернуть заказчика из названия конкурса, поэтому в поле "заказчик" копируется название 
    # название потом переписывается ( см далее )
    my $cu = $news->{ small_text };
    $news->{ customer } = $cu;

    # Try go to page and read full text:
    # RUS: На этом сайте в списке конкурсов текст отображается не полностью. Приходится за полным текстом заглядывать в страницу конкурса.
    $c->debug_explain("Go to $news->{ url } ...");
    $m->get( $news->{ url } );
    my $page = $m->content;
    my $full_text;

    if ( $page ){
        $page = encode("utf8",$page);
        ($full_text) = $page =~ /contentpaneopen.+?createdate.+?\<tr\>.+?\<td.+?\>\s*(.+?)\</ism;
        if ( $full_text ){
    	    $c->debug_explain("Full_text: '$full_text'");
    	    $news->{ small_text } = $full_text;
        }else{
	    $c->debug_explain("CAN'T get full_text. Will use '$l{$key}'. ".__FILE__." line:".__LINE__);
	}
    }
    else{
	$c->debug_explain("CAN'T get page $news->{ url }. Will use '$l{$key}'".__FILE__." line:".__LINE__);
    }
    #- end of try.

    #> В конченом счете вызывается $c->set_news для занесения конкурса в БД.
    # set_news() return 0-after error, 1-after insert news, 2-if news already exist and skipped, 3-if exist and updated
    
    my $set_rv = $c->set_news( $news, { update => 1 } ) 
	or $self->{error} = "Error while call set_news() (". __FILE__." line ".__LINE__."):\n ".$c->error(), return 0 ;
    $c->debug_explain(Dumper $news, "Set_news result: $set_rv");
    $inserted_cnt ++ if $set_rv == 1;
 }

 return $inserted_cnt;
}

sub new{
 #> Конструктор объекта, возвращает ссылку на объект.
 my $package = shift;
 my $self = {
    site_address => $site_address,
    
 };
 return bless $self;
}

sub error{ shift->{error} }
#> Возвращает последнюю ошибку из $self->{error}.

sub enabled{ return $enabled }
#> Возвращает значение переменной $enabled

1;
